package com.basic.model.quartz;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.basic.exception.QuartzException;
import com.basic.model.quartz.param.CronTaskParam;
import com.basic.model.quartz.param.TaskParam;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

@Slf4j
@Component
public class BasicJobManager {

    public final static String JOB_DATA = "jobData";

    @Autowired
    private Scheduler scheduler;

    /**
     * 获取定时器中的数据
     */
    public JobDataMap getJobDetail(String job, String group) throws SchedulerException {
        final Trigger trigger = TriggerBuilder.newTrigger().withIdentity(job, group).build();

        if (scheduler.checkExists(trigger.getKey())) {
            final JobDetail jobDetail = scheduler.getJobDetail(trigger.getJobKey());
            return jobDetail.getJobDataMap();
        } else {
            throw new QuartzException("任务不存在");
        }

    }


    /**
     * 添加定时任务(每隔intervalSeconds这么多秒执行一次)
     */
    public void addScheduleJob(TaskParam task, int intervalSeconds) throws SchedulerException {

        log.info("add schedule job start -> task: {}, interval: {}", task, intervalSeconds);

        final TaskParam.KeyBuilder keyBuilder = task.getKeyBuilder();
        final JobDetail detail = JobBuilder.newJob(BasicSchedulerJob.class)
                                            .withIdentity(keyBuilder.getName(), keyBuilder.getGroup())
                                            .usingJobData(JOB_DATA, task.encode())
                                            .build();

        final Trigger trigger = TriggerBuilder.newTrigger().withIdentity(keyBuilder.getName(), keyBuilder.getGroup())
                                                        .withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
                                                                .withIntervalInSeconds(intervalSeconds)
                                                                .withMisfireHandlingInstructionIgnoreMisfires()
                                                        )
                                                        .build();

        if (scheduler.checkExists(trigger.getKey())) {

            scheduler.pauseTrigger(trigger.getKey());
            scheduler.unscheduleJob(trigger.getKey());
        }

        scheduler.scheduleJob(detail, trigger);

        log.info("add schedule job success -> task: {}, interval: {}", task, intervalSeconds);

    }

    /**
     * schema服务器添加任务(具体时间执行)
     */
    public void addDelayJob(TaskParam task, Long date) throws SchedulerException {

        log.info("add delay job start -> task: {}, date: {}", task, date);
        TaskParam.KeyBuilder keyBuild = task.getKeyBuilder();

        JobDetail detail = JobBuilder.newJob(BasicSchedulerJob.class)
                .withIdentity(keyBuild.getName(), keyBuild.getGroup())
                .usingJobData(JOB_DATA, task.encode())
                .build();

        Trigger trigger;
        if(date != null) {
            trigger = TriggerBuilder.newTrigger().startAt(new Date(date))
                    .withIdentity(keyBuild.getName(), keyBuild.getGroup())
                    .build();
        }else {
            //触发delay job
            trigger = TriggerBuilder.newTrigger().withIdentity(keyBuild.getName(), keyBuild.getGroup())
                    .startNow()
                    .build();
        }

        if(scheduler.checkExists(trigger.getKey())) {

            scheduler.pauseTrigger(trigger.getKey());
            scheduler.unscheduleJob(trigger.getKey());
        }

        scheduler.scheduleJob(detail, trigger);

        log.info("add delay job success -> task: {}, date: {}", task, date);
    }

    /**
     * schema服务器添加任务(具体时间执行)
     */
    public void addCronJob(CronTaskParam task) throws SchedulerException {

        if (ObjectUtil.isNull(task) || ObjectUtil.isNull(task.getBodyFormat()) || StrUtil.isBlank(task.getBodyFormat().getCron()) || CronExpression.isValidExpression(task.getBodyFormat().getCron())) {
            throw new QuartzException("请传入正确的cron表达式");
        }

        log.info("add cron job start -> task: {}, cron: {}", task, task.getBodyFormat().getCron());
        final TaskParam.KeyBuilder keyBuild = task.getKeyBuilder();

        final JobDetail detail = JobBuilder.newJob(BasicSchedulerJob.class)
                    .withIdentity(keyBuild.getName(), keyBuild.getGroup())
                    .usingJobData(JOB_DATA, task.encode())
                    .build();

        final Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(keyBuild.getName(), keyBuild.getGroup())
                    .withSchedule(CronScheduleBuilder.cronSchedule(task.getBodyFormat().getCron()))
                    .build();

        if(scheduler.checkExists(trigger.getKey())) {

            scheduler.pauseTrigger(trigger.getKey());
            scheduler.unscheduleJob(trigger.getKey());
        }

        scheduler.scheduleJob(detail, trigger);

        log.info("add cron job success -> task: {}, cron: {}", task, task.getBodyFormat().getCron());
    }

    /**
     * schema服务器添加任务(具体时间执行)
     */
    public void updateJobCron(CronTaskParam task) throws SchedulerException {

        if (ObjectUtil.isNull(task) || ObjectUtil.isNull(task.getBodyFormat()) || StrUtil.isBlank(task.getBodyFormat().getCron()) || CronExpression.isValidExpression(task.getBodyFormat().getCron())) {
            throw new QuartzException("请传入正确的cron表达式");
        }

        log.info("update cron job start -> task: {}, cron: {}", task, task.getBodyFormat().getCron());
        TaskParam.KeyBuilder keyBuild = task.getKeyBuilder();
        TriggerKey triggerKey = TriggerKey.triggerKey(keyBuild.getName(), keyBuild.getGroup());
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        // 如果不存在创建一个定时任务
        if (trigger == null) {
            addCronJob(task);
            trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        }

        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(task.getBodyFormat().getCron())).build();
        //重置启动时间
        ((CronTriggerImpl)trigger).setStartTime(new Date());
        trigger.getJobDataMap().put(JOB_DATA, task.encode());

        scheduler.rescheduleJob(triggerKey, trigger);
        // 暂停任务
        if (task.getBodyFormat().getIsPause()) {
            pauseJob(task);
        }

        log.info("update cron job success -> task: {}, cron: {}", task, task.getBodyFormat().getCron());
    }


    /**
     * 移除定时器
     */
    public void removeJob(TaskParam task) {

        try {
            removeScheduleJob(task);
        } catch (SchedulerException ignore) {
            ignore.printStackTrace();
        }
    }

    private void removeScheduleJob(TaskParam task) throws SchedulerException {

        log.info("remove schedule job start -> task: {}", task);
        final TaskParam.KeyBuilder keyBuild = task.getKeyBuilder();

        final Trigger trigger = TriggerBuilder.newTrigger().withIdentity(keyBuild.getName(), keyBuild.getGroup())
                .build();

        if(scheduler.checkExists(trigger.getKey())) {

            scheduler.pauseTrigger(trigger.getKey());
            scheduler.unscheduleJob(trigger.getKey());
        }
    }

    /**
     * 暂停一个job
     * @param task /
     */
    public void pauseJob(CronTaskParam task){
        try {
            JobKey jobKey = JobKey.jobKey(task.getKeyBuilder().getName(), task.getKeyBuilder().getGroup());
            scheduler.pauseJob(jobKey);
        } catch (Exception e){
            log.error("定时任务暂停失败", e);
            throw new QuartzException("定时任务暂停失败");
        }
    }

}
